#include <bits/stdc++.h>
#include "EquationSolver.h"
using namespace std;

class fB1: public Function{
public:
    double operator () (const double &x) const{
        return 1/x-tan(x);
    }
}fb1;

class fB2: public Function{
public:
    double operator () (const double &x) const{
        return 1/x-pow(2,x);
    }
}fb2;

class fB3: public Function{
public:
    double operator () (const double &x) const{
        return pow(2,-x)+exp(x)+2*cos(x)-6;
    }
}fb3;

class fB4: public Function{
public:
    double operator () (const double &x) const{
        return (x*x*x+4*x*x+3*x+5)/(2*x*x*x-9*x*x+18*x-2);
    }
}fb4;

class fC: public Function{
public:
    double operator () (const double &x) const{
        return x-tan(x);
    }
    double posdev( const double &x) const{
        return 1-1/(cos(x)*cos(x));
    }
    double negdev( const double &x) const{
        return 1-1/(cos(x)*cos(x));
    }
}fc;

class fD1: public Function{
public:
    double operator () (const double &x) const{
        return sin(x/2)-1;
    }
}fd1;

class fD2: public Function{
public:
    double operator () (const double &x) const{
        return exp(x)-tan(x);
    }
}fd2;

class fD3: public Function{
public:
    double operator () (const double &x) const{
        return x*x*x - 12*x*x + 3*x + 1;
    }
}fd3;

const double L = 10, r = 1, V = 12.4;

class fE: public Function{
public:
    double operator () (const double &h) const{
        return L*(0.5*M_PI*r*r-r*r*asin(h/r)-h* sqrt(r*r-h*h))-V;
    }
    double posdev (const double &h) const{
        return L*(-r*1.0/sqrt(1.0-(h/r)*(h/r))-sqrt(r*r-h*h)+2*h*h/sqrt(r*r-h*h));
    }
    double negdev (const double &h) const{
        return L*(-r*1.0/sqrt(1.0-(h/r)*(h/r))-sqrt(r*r-h*h)+2*h*h/sqrt(r*r-h*h));
    }
} fe;

class fF: public Function{
private:
    double A, B, C, E;
public:
    fF(int l, int h, int D, double b){
        A = l*sin(b/180*M_PI);
        B = l*cos(b/180*M_PI);
        C = (h+0.5*D)*sin(b/180*M_PI)-0.5*D*tan(b/180*M_PI);
        E = (h+0.5*D)*cos(b/180*M_PI)-0.5*D;
    }
    double operator () (const double &x) const{
        return A*sin(x)*cos(x)+B*sin(x)*sin(x)-C*cos(x)-E*sin(x);
    }
    double posdev(const double &x) const{
        return A*(-sin(x)*sin(x)+cos(x)*cos(x))+2*B*cos(x)*sin(x)+C*sin(x)-E*cos(x);
    }
    double negdev(const double &x) const{
        return A*(-sin(x)*sin(x)+cos(x)*cos(x))+2*B*cos(x)*sin(x)+C*sin(x)-E*cos(x);
    }
};

int main(){
    cout << "Problem B" << endl;
    cout << "1.f(x)=1/x-tan(x) interval: [0,pi/2]" << endl;
    BisectionSolver FB1(fb1, 0, M_PI/2);
    FB1.root();
    cout << "2.f(x)=1/x-2^x interval: [0,1]" << endl;
    BisectionSolver FB2(fb2);
    FB2.root();
    cout << "3.f(x)=2^-x-e^x+2cosx-6 interval: [1,3]" << endl;
    BisectionSolver FB3(fb3, 1, 3);
    FB3.root();
    cout << "4.f(x)=(x^3+4x^2+3x+5)/(2x^3-9x^2+18x-2) interval: [0,4]" << endl;
    BisectionSolver FB4(fb4, 0, 4);
    FB4.root();
    cout << endl;

    cout << "Problem C" << endl;
    cout << "1.x=tanx initial point: 0.45" << endl;
    NewtonSolver FC1(fc, 4.5);
    FC1.root();
    cout << "2.x=tanx initial point: 0.77" << endl;
    NewtonSolver FC2(fc, 7.7);
    FC2.root();
    cout << endl;

    cout << "Problem D" << endl;
    cout << "1.f(x)=sin(x/2)-1 initial point: 0,pi/2" << endl;
    SecantSolver FD1(fd1, 0, M_PI/2);
    FD1.root();
    cout << "2.f(x)=e^x-tanx initial point: 1,1.4" << endl;
    SecantSolver FD2(fd2, 1, 1.4);
    FD2.root();
    cout << "3.f(x)=x^3-12x^2+3x+1 initial point: 0,-0.5" << endl;
    SecantSolver FD3(fd3, 0, -0.5);
    FD3.root();
    cout << endl;

    cout << "Problem E" << endl;
    BisectionSolver FE1(fe);
    FE1.root();
    NewtonSolver FE2(fe);
    FE2.root();
    SecantSolver FE3(fe);
    FE3.root();
    cout << endl;

    cout << "Problem F" << endl;
    cout << "1." << endl;
    fF ff1(89, 49, 55, 11.5);
    NewtonSolver FF1(ff1, 33.0/180.0*M_PI);
    FF1.root();
    cout << "2." << endl;
    fF ff2(89, 49, 30, 11.5);
    NewtonSolver FF2(ff2, 33.0/180.0*M_PI);
    FF2.root();
    cout << "3." << endl;
    cout << "initial point: 30degree 33degree" << endl;
    SecantSolver FF3(ff1, 30.0/180.0*M_PI, 33.0/180.0*M_PI);
    FF3.root();
    cout << endl;
    cout << "initial point: -180degree 0degree" << endl;
    SecantSolver FF4(ff1, -M_PI, 0);
    FF4.root();
    cout << endl;
    cout << "initial point: 180degree 360degree" << endl;
    SecantSolver FF5(ff1, M_PI, 2*M_PI);
    FF5.root();

    return 0;
}